// License Notification
//======================================================
// Copyright (c) 2010 Channel Intelligence Inc.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// ======================================================




using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Xml;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Text.RegularExpressions;
using System.Reflection;
using CIP4.Common;

#pragma warning disable 1591        // disable missing documentation comments warning
namespace CIP4.RulesEngine
{
    /// <summary>
    /// Required properties Condition 
    /// 
    /// </summary>
    public partial class ConditionalActionType : BaseActionType 
    {
        private IBooleanValue m_Condition;
        /// <summary>
        /// Single valued IBooleanValue object property: : required 
        /// 
        /// </summary>
        public IBooleanValue Condition
        {
            get
            {
                return m_Condition;
            }
            set
            {
                m_Condition = value;
            }
        }
        private BaseActionType m_ThenAction;
        public BaseActionType ThenAction
        {
            get { return m_ThenAction; }
            set { m_ThenAction = value; }
        }
        public List<BaseActionType> Actions
        {
            get
            {
                if (m_ThenAction == null)
                    m_ThenAction = new ActionSequenceType();
                if (!(m_ThenAction is ActionSequenceType))
                    m_ThenAction = new ActionSequenceType(new List<BaseActionType> { m_ThenAction } );
                return ((ActionSequenceType)m_ThenAction).Actions;
            }
        }
        private BaseActionType m_ElseAction;
        public BaseActionType ElseAction
        {
            get { return m_ElseAction; }
            set { m_ElseAction = value; }
        }
        /// <summary>
        /// Multi valued BaseActionType object value collection property: maxOccurs 79228162514264337593543950335 not required 
        /// </summary>
        public List<BaseActionType> ElseActions
        {
            get
            {
                if (m_ElseAction == null)
                    m_ElseAction = new ActionSequenceType();
                if (!(m_ElseAction is ActionSequenceType))
                    m_ElseAction = new ActionSequenceType(new List<BaseActionType> { m_ElseAction });
                return ((ActionSequenceType)m_ElseAction).Actions;
            }
        }
        public ConditionalActionType() { }
        public ConditionalActionType(IBooleanValue ConditionValue)
        {
            Condition = ConditionValue;
        }
        public ConditionalActionType(IBooleanValue condition, BaseActionType action)
        {
            Condition = condition;
            ThenAction = action;
        }
        public ConditionalActionType(IBooleanValue condition, BaseActionType action, BaseActionType elseAction)
        {
            Condition = condition;
            ThenAction = action;
            ElseAction  = elseAction;
        }
        public ConditionalActionType(IBooleanValue condition, List<BaseActionType> actions)
        {
            Condition = condition;
            if (actions.Count > 1)
                ThenAction = new ActionSequenceType(actions);
            if (actions.Count == 1)
                ThenAction = actions[0];
        }
        public ConditionalActionType(IBooleanValue condition, List<BaseActionType> actions, List<BaseActionType> elseActions)
        {
            Condition = condition;
            if (actions.Count > 1)
                ThenAction = new ActionSequenceType(actions);
            if (actions.Count == 1)
                ThenAction = actions[0];

            if (elseActions.Count > 1)
                ThenAction = new ActionSequenceType(elseActions);
            if (elseActions.Count == 1)
                ThenAction = elseActions[0];
        }
        public ConditionalActionType(XElement caNode, BaseActionType owner)
        {
            ObjectOwner = owner;
            Initialize(caNode);
        }
        public ConditionalActionType(XElement caNode)
        {
            Initialize(caNode);
        }
        private void Initialize(XElement caNode)
        {
            XElement originNode = caNode.Element(XName.Get("Origin", RuleXmlNS));
            if (originNode != null)
                Origin = originNode.Value == "FromCurrentType" ? ActionOriginType.FromCurrentType : ActionOriginType.FromPropertyType;
            XAttribute usageNode = caNode.Attribute(XName.Get("Usage", RuleXmlNS));
            if (usageNode != null)
                Usage = ActionUsageEnumFromString(usageNode.Value);
            XElement descriptionNode = caNode.Element(XName.Get("Description", RuleXmlNS));
            if (descriptionNode != null)
                Description = descriptionNode.Value;
            XElement conditionNode = caNode.Element(XName.Get("Condition", RuleXmlNS));
            if (conditionNode != null)
                Condition = (IBooleanValue)CIValueType.Initialize((XElement)conditionNode.FirstElement());
            
            XElement thenActionNode = caNode.Element(XName.Get("ThenAction", RuleXmlNS));
            if (thenActionNode != null)
                ThenAction = BaseActionType.Initialize(thenActionNode.FirstElement(), this);
            XElement elseActionNode = caNode.Element(XName.Get("ElseAction", RuleXmlNS));
            if (elseActionNode != null)
                ElseAction = BaseActionType.Initialize(elseActionNode.FirstElement(), this);

            XElement actionsNode = caNode.Element(XName.Get("Actions", RuleXmlNS));
            if (actionsNode != null)
                foreach (XElement actionNode in actionsNode.Elements())
                    Actions.Add(BaseActionType.Initialize(actionNode, this));
            XElement elseActionsNode = caNode.Element(XName.Get("ElseActions", RuleXmlNS));
            if (elseActionsNode != null)
                foreach (XElement actionNode in elseActionsNode.Elements())
                    ElseActions.Add(BaseActionType.Initialize(actionNode, this));
            InitializeParameters(caNode);
        }
        public override void Execute(IDataPacketType data)
        {
            if (data.PacketStats != null)
                data.PacketStats.TestedObjectCount += 1;
            if (Condition.Value(data))
            {
                if (data.PacketStats != null)
                    data.PacketStats.ActedOnObjectCount += 1;
                foreach (BaseActionType action in Actions)
                    action.Execute(data);
            }
            else
            {
                if (data.PacketStats != null)
                    data.PacketStats.ActedOnObjectCount += 1;
                foreach (BaseActionType action in ElseActions)
                    action.Execute(data);
            }
        }
        public override bool Check(IDataPacketType data)
        {
            bool result = true;
            if (Condition == null)
            {
                data.Logger(MajorEnum.Error, MinorEnum.ExpressionStructure, "ConditonalAction is missing the condition", new object[] { this.ToString() });
                result = false;
            }
            else
                Condition.Check(data);
            if (ThenAction == null && ElseAction == null)
            {
                data.Logger(MajorEnum.Error, MinorEnum.ExpressionStructure, "ConditonalAction has no actions", new object[] { this.ToString() });
                result = false;
            }
            else
            {
                if (ThenAction != null)
                    ThenAction.Check(data);
                if (ElseAction != null)
                    ElseAction.Check(data);
            }
            return result;
        }
        public override void XmlFor(XmlWriter xwrtr, bool writeNamespaceAttribute)
        {
            xwrtr.WriteStartElement("ConditionalAction");
            if (writeNamespaceAttribute)
                xwrtr.WriteAttributeString("xmlns", RuleXmlNS);
            if (Origin.HasValue)
                xwrtr.WriteElementString("Origin", Origin.ToString());
            if (Usage.HasValue && Usage != ActionUsageEnum.None)
                xwrtr.WriteAttributeString("Usage", Usage.ToString());
            if (!string.IsNullOrEmpty(Description))
                xwrtr.WriteElementString("Description", Description);
            XmlForFormalParameters(xwrtr);
            if (Condition != null)
            {
                bool writeXmlNs = false;
                xwrtr.WriteStartElement("Condition");
                Condition.XmlFor(xwrtr, writeXmlNs);
                xwrtr.WriteEndElement();
            }
            if (ThenAction != null)
            {
                xwrtr.WriteStartElement("ThenAction");
                ThenAction.XmlFor(xwrtr, false);
                xwrtr.WriteEndElement();
            }
            if (ElseAction != null)
            {
                xwrtr.WriteStartElement("ElseAction");
                ElseAction.XmlFor(xwrtr, false);
                xwrtr.WriteEndElement();
            }
            xwrtr.WriteEndElement();
        }
        /// <summary>
        /// For an explanation of how to use this see the comment on ActionSequence.ResolveName
        /// </summary>
        /// <param name="qualifiedName"></param>
        public override void ResolveName(string qualifiedName)
        {
            Condition.ResolveName(qualifiedName);
            if (ThenAction != null)
                ThenAction.ResolveName(qualifiedName);
            if (ElseAction != null)
                ElseAction.ResolveName(qualifiedName);
        }
        public override BaseActionType Copy()
        {
            return new ConditionalActionType(XElement.Parse(XmlFor()), null);
        }
        public override string ToString(string indent)
        {
            string s = "";
            if (!string.IsNullOrEmpty(Description))
                s += indent + "' " + Description + Environment.NewLine;
            s = indent + "IF ";
            if (Condition == null)
                s += "<missing condition> THEN" + Environment.NewLine;
            else
                s += Condition.ToString() + " THEN" + Environment.NewLine;
            if (ThenAction == null && ElseAction == null)
                s += indent + "    <missing action>" + Environment.NewLine;
            else if (ThenAction != null && (!(ThenAction is ActionSequenceType) || ((ActionSequenceType)ThenAction).Actions.Count > 0))
            {
                s += ThenAction.ToString(indent + "    ") + Environment.NewLine;
            }
            if (ElseAction != null && (!(ElseAction is ActionSequenceType) || ((ActionSequenceType)ElseAction).Actions.Count > 0))
            {
                s += indent + "ELSE" + Environment.NewLine;
                s += ElseAction.ToString(indent + "    ") + Environment.NewLine;
            }
            return s + indent + "END IF";
        }
        public override string ToString()
        {
            return ToString("");
        }
    }
}
